local skynet = require "skynet"
require "skynet.manager"
local mysql = require "mysql"
local log = require "Log"
local CMD = {}
local pool = {}

local maxconn
local index = 2
local function getconn(sync)
	local db
	if sync then
		db = pool[1]
	else
		db = pool[index]
		assert(db)
		index = index + 1
		if index > maxconn then
			index = 2
		end
	end
	return db
end

--正常情况下，每5分钟运行一次保活
--连接断开情况下，每1秒钟运行一次保活，并且mysql driver底层会进行重连
function keep_self_alive()
    skynet.fork(function ()
        while true do
            for k,db in pairs(pool) do
            	db:query('select 1')
            	--print('_______select 1')
            end
            skynet.sleep(100*60*3) --1秒
        end
    end)
end

function CMD.start(args)
	maxconn = tonumber(skynet.getenv("mysql_maxconn")) or 10
	assert(maxconn >= 2)
	skynet.register(args.serviceName)
	for i = 1, maxconn do
		local db = mysql.connect{
			host = args.host,
			port = args.port,
			database = args.database,
			user = args.user,
			password = args.password,	
			max_packet_size = 1024 * 1024,
		}
		if db then
			table.insert(pool, db)
			--db:query("set charset utf8")
		else
			skynet.error("mysql connect error")
		end
		--print("_____________mysql_start___connect____",db)
	end
	keep_self_alive()
end

-- sync为false或者nil，sql为读操作，如果sync为true用于数据变动时同步数据到mysql，sql为写操作
-- 写操作取连接池中的第一个连接进行操作
function CMD.execute(sql, sync)
	local db = getconn(sync)
    local ok,result = x_pcall(function(sql, ...)
    	local result = db:query(sql)
    	if result.errno or result.err then
    		log.error(' DB##############'..' Have'..' errno:'..tostring(result.errno)..' errmsg:'..tostring(result.err)..' error sql: '..sql)
    		return nil
    	end
    	return result
    end, sql)
    if not ok then
        log.error('[ DB##############'..' not ok! result: ', result, ' error sql: ', sql)
        return nil
    end	
	--return db:query(sql)
	return result
end

function CMD.stop()
	for _, db in pairs(pool) do
		db:disconnect()
	end
	pool = {}
end

skynet.start(function()
	skynet.dispatch("lua", function(session, source, cmd, ...)
		local f = assert(CMD[cmd], cmd .. "not found")
		skynet.retpack(f(...))
	end)
end)
